package no.nordicsemi.android.dfuupdate;

import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;

import java.util.List;
import java.util.Objects;
import java.util.UUID;

import no.nordicsemi.android.dfuupdate.dfu.DfuActivity;
//单个设备AT，DFU激活和升级
public class DeviceControlActivity extends AppCompatActivity {

    String selectedDeviceName;
    String selectedDeviceMac;

    TextView devName;
    TextView devMac;
    TextView devCon;
    Button toAt;
    Button toDfu;
    Boolean isConnected = false;

    private BluetoothLeService mBluetoothLeService;

    public static final UUID WRITE_UUID = UUID.fromString("6e400002-b5a3-f393-e0a9-e50e24dcca9e");
    public static final UUID READ_UUID = UUID.fromString("6e400003-b5a3-f393-e0a9-e50e24dcca9e");
    public static final UUID DFU_UUID = UUID.fromString("8ec90003-f315-4f60-9fb8-838830daea50");
    public static final UUID DFU_DESCRIPTOR = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");

    private BluetoothGattCharacteristic writeCh;
    private BluetoothGattCharacteristic readCh;
    private BluetoothGattCharacteristic bootReadCh;
    private BluetoothGattCharacteristic bootWriteCh;
    private BluetoothGattCharacteristic bootNotCh;

    private boolean dfuFlag = false;

    private final ServiceConnection mServiceConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
            Log.d("Service", "getService");
            if (!mBluetoothLeService.initialize()) {
                Log.e("DCA_onServCon", "Unable to initialize Bluetooth");
                finish();
            }
            // Automatically connects to the device upon successful start-up initialization.
            mBluetoothLeService.connect(selectedDeviceMac);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mBluetoothLeService = null;
            Log.d("onServiceDisconnected", "service disconnected");
        }
    };

    // Handles various events fired by the Service.
    // ACTION_GATT_CONNECTED: connected to a GATT server.
    // ACTION_GATT_DISCONNECTED: disconnected from a GATT server.
    // ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services.
    // ACTION_DATA_AVAILABLE: received data from the device.  This can be a result of read
    //                        or notification operations.
    private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            Log.d("BroadcastReceiver-92", action);
            if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
                isConnected = true;
                updateConnectionState("Connected");
                invalidateOptionsMenu();
                toDfu.setEnabled(true);
                bootReadCh = new BluetoothGattCharacteristic(DFU_UUID, BluetoothGattCharacteristic.PROPERTY_READ, BluetoothGattCharacteristic.PERMISSION_READ);
                bootWriteCh = new BluetoothGattCharacteristic(DFU_UUID, BluetoothGattCharacteristic.PROPERTY_WRITE, BluetoothGattCharacteristic.PERMISSION_WRITE);
                Toast.makeText(DeviceControlActivity.this, "蓝牙连接成功!", Toast.LENGTH_SHORT).show();
            } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
                Log.d("BroadcastReceiver", "蓝牙连接断开");
                isConnected = false;
                updateConnectionState("Disconnected");
                invalidateOptionsMenu();
                toDfu.setEnabled(false);
                Toast.makeText(DeviceControlActivity.this, "蓝牙连接断开!", Toast.LENGTH_SHORT).show();
                if (dfuFlag) {
                    Intent dfuIntent = new Intent(DeviceControlActivity.this, DfuActivity.class);
                    Bundle dfuBundle = new Bundle();
                    dfuBundle.putString("mac_address", macAddOne(selectedDeviceMac));
                    dfuIntent.putExtras(dfuBundle);
                    startActivity(dfuIntent);
                    finish();
                }
            } else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
                // Show all the supported services and characteristics on the user interface.
                displayGattServices(mBluetoothLeService.getSupportedGattServices());
            }

        }
    };


    private void updateConnectionState(final String text) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                devCon.setText(text);
            }
        });
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_device_control);
        final Toolbar toolbar = findViewById(R.id.toolbar_actionbar);
        setSupportActionBar(toolbar);
        Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
        Objects.requireNonNull(getSupportActionBar()).setDisplayShowCustomEnabled(true);
        Intent intent = getIntent();
        Bundle bundle = intent.getExtras();
        selectedDeviceName = bundle.getString("extra_device_name");
        if (selectedDeviceName == null) selectedDeviceName = "N/A";
        Log.d("name", selectedDeviceName);
        selectedDeviceMac = bundle.getString("extra_mac_address");
        Log.d("mac", (selectedDeviceMac == null) ? "null" : selectedDeviceMac);
        isConnected = bundle.getBoolean("isConnected");
        Log.d("ISCONNECTED", isConnected.toString());
        dfuFlag = false;

        init();
        Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
        bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
        if (savedInstanceState != null) {
            savedInstanceState.getBoolean("isConnected");
            Log.d("SavInst", "not null");
        }
        if (isConnected == null) isConnected = false;
        updateConnectionState(isConnected.toString());
        // Bundle bundl = getIntent().getExtras();

    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    public void init() {
        devName = (TextView) findViewById(R.id.device_name);
        devName.setText(selectedDeviceName);
        devMac = (TextView) findViewById(R.id.mac_addr);
        devMac.setText(selectedDeviceMac);
        devCon = (TextView) findViewById(R.id.con_stat);
        toAt = (Button) findViewById(R.id.at_cmd);
        toDfu = (Button) findViewById(R.id.boot_dfu);
        if (isConnected)
            toDfu.setEnabled(true);
        else
            toDfu.setEnabled(false);
        devCon = (TextView) findViewById(R.id.con_stat);

        toAt.setOnClickListener(v -> {
            Toast.makeText(DeviceControlActivity.this, "to AT CMD", Toast.LENGTH_SHORT).show();
            Intent atIntent = new Intent(DeviceControlActivity.this, AtModeActivity.class);
            Bundle bundle = new Bundle();
            bundle.putString("extra_device_name", selectedDeviceName);
            bundle.putString("extra_device_mac", selectedDeviceMac);
            if (isConnected) bundle.putString("isConnected", "true");
            else bundle.putString("isConnected", "false");
            if (readCh != null)
                bundle.putParcelable("read_chara", readCh);
            if (writeCh != null)
                bundle.putParcelable("write_chara", writeCh);
            atIntent.putExtras(bundle);
            startActivity(atIntent);
            finish();
        });

        toDfu.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO DFU init
                Toast.makeText(DeviceControlActivity.this, "to DFU BOOTLOADER", Toast.LENGTH_SHORT).show();

                //mBluetoothLeService.enableNotification();

                for (BluetoothGattDescriptor descriptor : bootWriteCh.getDescriptors()) {
                    Log.d("DESCRIPTORS::", descriptor.toString());
                    Log.d("DESCRIPTORS::", "[" + descriptor.getUuid().toString().equals(DFU_DESCRIPTOR.toString()) + "]");
                    boolean b1 = descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
                    if (b1) {
                        mBluetoothLeService.enableNotification(descriptor);
                    }
                }

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Log.d("NOTIFICATION", "notification sent");
                mBluetoothLeService.setCharacteristicNotification(bootWriteCh, true);
                Log.d("INDICATION", "indication enabled");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                mBluetoothLeService.setCharacteristicNotification(bootWriteCh, true);
                Log.d("INDICATION", "write enabled");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                mBluetoothLeService.writeData(new byte[]{0x01}, bootWriteCh);
                Log.d("sent data", "0x01");
                dfuFlag = true;
            }
        });
        //dfu 升级
        findViewById(R.id.direct_dfu).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent newIntent = new Intent(DeviceControlActivity.this, DfuActivity.class);
                Bundle macB = new Bundle();
                macB.putString("mac_address", selectedDeviceMac);
                macB.putString("mac_name", selectedDeviceName);
                macB.putBoolean("select_device", true);
                newIntent.putExtras(macB);
                startActivity(newIntent);
                finish();
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
        if (mBluetoothLeService != null) {
            final boolean result = mBluetoothLeService.connect(selectedDeviceMac);
            Log.d("DevConAct_onRes", "Connect request result = " + result);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(mGattUpdateReceiver);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(mServiceConnection);
        mBluetoothLeService = null;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.connect, menu);
        if (isConnected) {
            menu.findItem(R.id.menu_connect).setVisible(false);
            menu.findItem(R.id.menu_disconnect).setVisible(true);
        } else {
            menu.findItem(R.id.menu_connect).setVisible(true);
            menu.findItem(R.id.menu_disconnect).setVisible(false);
        }
        return true;

    }

    @Override
    public boolean onOptionsItemSelected(final MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                onBackPressed();
                break;
            case R.id.menu_connect: {
                mBluetoothLeService.connect(selectedDeviceMac);
                return true;
            }
            case R.id.menu_disconnect: {
                mBluetoothLeService.disconnect();
                return true;
            }
        }
        if (android.R.id.home == (item.getItemId())) {
            onBackPressed();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    private void displayGattServices(List<BluetoothGattService> gattServices) {
        if (gattServices == null) return;

        // Loops through available GATT Services.
        for (BluetoothGattService gattService : gattServices) {

            List<BluetoothGattCharacteristic> gattCharacteristics =
                    gattService.getCharacteristics();


            // Loops through available Characteristics.
            for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
                BluetoothGattCharacteristic tempCh = gattCharacteristic;
                String uuids = tempCh.getUuid().toString();

                Log.d("CHA", "'" + uuids + "'");
                if (uuids.equals(READ_UUID.toString())) {
                    //mBluetoothLeService.setReadCha(tempCh);
                    //mBluetoothLeService.readCharacteristic(tempCh);
                    readCh = tempCh;
                    mBluetoothLeService.setCharacteristicNotification(readCh, true);
                    Log.d("READ kEY", "DONE");
                } else if (uuids.equals(WRITE_UUID.toString())) {
                    writeCh = tempCh;
                    Log.d("WRITE KEY", "DONE");
                } else if (uuids.equals(DFU_UUID.toString())) {
                    Log.d("DFU KEY", "FIND");
                    bootWriteCh = tempCh;
                }

            }
        }
    }

    private static IntentFilter makeGattUpdateIntentFilter() {
        final IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
        intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
        intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
        intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);
        return intentFilter;
    }

    private String macAddOne(String mac) {
        if (mac.length() != 17) {
            Log.d("INVALID_MAC", "device origin mac address invalid formatt");
            return null;
        }
        StringBuilder sb1 = new StringBuilder();
        for (int i = 0; i < mac.length(); i++) {
            if (':' != (mac.charAt(i)))
                sb1.append(mac.charAt(i));
        }
        long dec = Long.parseLong(sb1.toString(), 16);
        String hex = Long.toHexString(dec + 1);
        if (hex.length() != 12) {
            Log.d("INVALID_MAC", "device add 1 mac address invalid formatt");
            return null;
        }
        StringBuilder sb2 = new StringBuilder();
        for (int j = 0; j < 12; j++) {
            sb2.append(hex.charAt(j));
            if (j % 2 == 1 && j < 11)
                sb2.append(":");
        }
        String ret = sb2.toString();
        ret = ret.toUpperCase();
        return ret;
    }
}
